#include "UdpClient.hpp"

using namespace LogArea;

struct sockaddr_in server;
int sockfd = -1;


// 用户退出
void ClientQuit(int signo)
{
    (void)signo;
    const std::string quit = "QUIT";
    int n = ::sendto(sockfd, quit.c_str(), quit.size(), 0, CONV(&server), sizeof(server));
    (void)n;
    exit(0);
}

// void *Recver(void *args)
// {
//     while (true)
//     {
//         (void)args;
//         struct sockaddr_in temp;
//         socklen_t len = sizeof(temp);
//         char buffer[1024];
//         int n = ::recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, CONV(&temp), &len);
//         if (n > 0)
//         {
//             buffer[n] = 0;
//             std::cerr << buffer << std::endl; // 代码没问题，重定向也没问题，管道读写同时打开，才会继续向后运行
//             // fprintf(stderr, "%s\n", buffer);
//             // fflush(stderr);
//         }
//     }
// }

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        LOG(LogLevel::ERROR) << "Usage error, argc should be: 3";
        DIE(USAGE_ERR);
    }

    signal(2, ClientQuit);

    std::string serverip = argv[1];           // IP地址
    uint16_t serverport = std::stoi(argv[2]); // 服务器端口号

    sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        LOG(LogLevel::FATALER) << "socket error: " << strerror(errno);
        DIE(SOCKET_ERR);
    }

    // 填充 server 信息,用于后面 recvfrom 与服务器通信
    memset(&server, 0, sizeof(server)); // 将 server 结构体中内容清空
    server.sin_family = AF_INET;
    server.sin_port = ::htons(serverport);
    server.sin_addr.s_addr = ::inet_addr(serverip.c_str()); // 将服务器 ip 地址从网络转为主机


    // pthread_t tid;
    // pthread_create(&tid, nullptr, Recver, nullptr);

    // 1.2 启动的时候，给服务器推送消息即可
    const std::string online = " ... 来了哈!";
    int n = ::sendto(sockfd, online.c_str(), online.size(), 0, CONV(&server), sizeof(server));

    while (true)
    {
        std::cout << "Please Enter: ";
        std::string message;
        std::getline(std::cin, message);

        // client 不需要bind吗？socket <-> socket
        // client必须也要有自己的ip和端口！但是客户端，不需要自己显示的调用bind！！
        // 而是，客户端首次sendto消息的时候，由OS自动进行bind
        // 1. 如何理解client自动随机bind端口号？ 一个端口号，只能被一个进程bind
        // 2. 如何理解server要显示的bind？服务器的端口号，必须稳定！！必须是众所周知且不能改变轻易改变的!

        // 向服务器发送消息
        ssize_t n = ::sendto(sockfd, message.c_str(), message.size(), 0, CONV(&server), sizeof(server));
        (void)n;
    }

    return 0;
}